//
//  WZPeripheralManager.swift
//  BLE-Peripheral
//
//  Created by wujia121 on 2018/2/8.
//  Copyright © 2018年 steven. All rights reserved.
//

import UIKit
import CoreBluetooth

let WZServeUUID = "CAA1"//"10086"
let WZCharaUUID = "CAA2"//"10000"

class WZPeripheralManager: NSObject {
    ///公开:单例类方法，此处static等价于class，是类属性的修饰词
    static let shared  = WZPeripheralManager()
    
    ///私有:外设管理者(此处self就是shared对象，并不是WZPeripheralManager类对象)
    /*
     CBPeripheralManagerOptionShowPowerAlertKey
     CBPeripheralManagerOptionRestoreIdentifierKey
     */
    fileprivate lazy var manager = CBPeripheralManager(delegate: self, queue: DispatchQueue.main, options:[CBPeripheralManagerOptionShowPowerAlertKey:true]) //系统设置中蓝牙选项没打开时自动弹框
    
    ///私有:外设对象(本例中外设只有一个,即安装了本App的iPhone手机)
    fileprivate var myPeripheral : CBPeripheral?
    
    //私有:单例私有化init方法
    private override init(){
        super.init()
    }
    
    //公开方法
    public func checkAuthorizeStatus() -> Bool {
        
        //此行代码主要不是为了判断，而是为了调用懒加载，使其创建manager //第一次真正使用manager(类似PhotoKit)，系统才会弹框显示info.plist中添加的授权内容
        print(manager.description)
        
        let status = CBPeripheralManager.authorizationStatus()
        if status == .authorized {
            self.showText("用户已授权App使用BLE服务")
            return true
        } else {            
            return false
        }
    }
    
    
}


extension WZPeripheralManager: CBPeripheralManagerDelegate {
    
    /*
     public enum CBManagerState : Int {
     case unknown       未知
     case resetting     正在重置
     case unsupported   当前设备不支持蓝牙
     case unauthorized  当前蓝牙设备未通过苹果验证
     case poweredOff    未启动
     case poweredOn     启动，可正常使用
     }
     */
    /// @required必须实现: 第一次创建CBPeripheralManager对象完毕，就会回调此代理方法
    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
        if peripheral.state == .poweredOn { //特别注意:此处虽叫外设,但明明是外设管理者
            
            //如果正在广播，需要先停止
            if manager.isAdvertising {
                manager.stopAdvertising()
            }
            
            //验证此处的管理者是不是属性manager
            let testStr = String(format: "manager:%p -- peripheral:%p", arguments: [self.manager,peripheral])
            self.showText(testStr)
            
            //外设：设置服务、特征、开始广播
            self.setupServeAndChara()
            
        } else {
            let status = peripheral.state.rawValue
            self.showText("蓝牙外设不可用(0:未知 1:正在重置 2:不支持蓝牙 3:未认证 4:未开机 5:正常)，原因:" + String(status) )
            
            UIAlertController.showAlertController(style: .alert, title: "蓝牙设备无法使用", message: "(0:未知 1:正在重置 2:不支持蓝牙 3:未认证 4:未开机 5:正常), 当前:\(peripheral.state.rawValue)", okActionTitle: "确定", okAction: nil, cancelActionTitle: nil, cancelAction: nil)
        }
    }
    
    func setupServeAndChara() -> Void {
        
        /*
         一个周边peripheral的服务可以是主要的也可以是次要的。如心率检测器的主要服务是显示心率监测数据，而第二个服务可能是显示电池数据，如果属性是Yes那么服务就是主要类型
         */
        let service = CBMutableService(type: CBUUID(string: WZServeUUID), primary: true)
        /*
         public struct CBCharacteristicProperties : OptionSet {}
         Swift中的OptionSet用来替代OC中的位枚举，但写法为[.swimming, .cycling, .running]
         实际开发中一般建立2个特征：一个read+notify，一个write+notify，每个特征都必须带上notify，否则中心设备无法订阅该特征
         本例为了方便使用一个特征来读和写数据
         */
        let chara = CBMutableCharacteristic(type: CBUUID(string: WZCharaUUID), properties: [.read, .write, .notify], value: nil, permissions: [.readable, .writeable])
        
        service.characteristics = [chara]
        self.manager.add(service)
        
        /*
         only two of the keys are supported for peripheral manager objects:
         CBAdvertisementDataLocalNameKey
         CBAdvertisementDataServiceUUIDsKey
         */
        self.manager.startAdvertising([CBAdvertisementDataLocalNameKey : "MI-Ring", //这是广播出去的名字，通过peripheral.name获取的名字是iphone的名字：Sjcam-test
                                       CBAdvertisementDataServiceUUIDsKey : [CBUUID(string: WZServeUUID)] //数组
                                       ])
        
    }
    
    
    /// 外设 添加 服务 完毕，是否成功看error
    func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
        self.showText(#function + " ---err:" + error.debugDescription)
    }
    
    /// 开始广播
    func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
        self.showText(#function + " ---err:" + error.debugDescription)
    }
    
    /// 收到read请求
    func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {

        //打印中心设备的相关数据
        let str = " ---外设收到中心设备" + request.central.identifier.uuidString + "想要通过特征:" + request.characteristic.uuid.uuidString + "读取数据offset:" + String(request.offset)
        self.showText(#function + str)
        
        //设置请求响应数据
        request.value = "我是wz创建的外设".data(using: .utf8)
        
        //回复中心设备的请求
        peripheral.respond(to: request, withResult: CBATTError.success)
    }
    
    /// 收到写入请求
    func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
        //let str = requests.first?.description ?? ""
        //self.showText(#function + str)
        let data = requests.first?.value ?? Data()
        let str = String(data: data, encoding: .utf8) ?? ""
        self.showText(#function + "---" + str)
    }
    
    /// 中心设备 订阅了 外设的 某个特征
    func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
        self.showText(#function)
    }

    ///
    func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
        self.showText(#function)
    }
    
    /// 中心设备 取消 订阅 外设 某个特征
    func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic)
    {
        self.showText(#function)
    }
    
    
    func peripheralManager(_ peripheral: CBPeripheralManager, willRestoreState dict: [String : Any]) {
        self.showText(#function)
        
    }
}

extension WZPeripheralManager {
    func showText(_ str:String) -> Void {
        let txtView = RootVC?.view.viewWithTag(6666) as? UITextView
        txtView?.text = (txtView?.text ?? "") + "\n\n" + str
        print(txtView?.text ?? "")
    }
    
}



